package com.base.repository;

import java.io.Serializable;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import javax.ejb.Stateless;
import javax.persistence.Column;
import javax.persistence.EmbeddedId;
import javax.persistence.EntityManager;
import javax.persistence.Id;
import javax.persistence.LockModeType;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;

import com.base.util.Exists;
import com.base.util.ReflectUtil;


@Stateless
public class BasicRepositoryImpl<T> implements BasicRepository<T> {
    		
	private static final long serialVersionUID = -7983841124135403484L;
	@PersistenceContext(unitName = "o2o_op_oracle")
	protected EntityManager entityManager;

	@Override
	public boolean detach(T t) {
		entityManager.detach(t);
		return true;
	}

	@Override
	public T save(T t) {
		entityManager.persist(t);
		return t;
	}

	@Override
	public T merge(T t) {
		return entityManager.merge(t);
	}

	@Override
	public T update(T t) {
		entityManager.merge(t);
	
		return t;
	}

	@Override
	public boolean removeById(Class<T> clazz, Serializable id) {
		Exists<Field> existsFields=ReflectUtil.getFieldValue(clazz, "id", Id.class);
		if(existsFields.isExists()){
			String hql = "delete from " + clazz.getSimpleName() + " o where o.id=:id";
			Map<String, Object> map = new HashMap<String, Object>();
			map.put("id", id);
			executeUpdate(hql, map);
			return true;
		}else{
			Exists<T> exists=findById(clazz, id);
			if(exists.isExists()){
				remove(exists.getObject());
				return true;
			}
			return false;
		}
	}

	@Override
	public boolean remove(T t) {
		try {
			Exists<Object> exists = ReflectUtil.getFieldValue(t, "id", Id.class);
			if (exists.isExists()) {
				String hql = "delete from " + t.getClass().getSimpleName() + " o where o.id=:id";
				Map<String, Object> map = new HashMap<String, Object>();
				map.put("id", exists.getObject());
				executeUpdate(hql, map);
			} else {
				entityManager.remove(t);
			}
			return true;
		} catch (Exception e) {
			return false;
		}
	}
    
	@SuppressWarnings("rawtypes")
	public String getIdColumName(Class clazz){
		Field fields[] = clazz.getDeclaredFields();
		for (int i = 0; i < fields.length; i++) {
			Field f = fields[i];
			Column c = f.getAnnotation(Column.class);
			if (c != null) {
				if (f.getAnnotation(Id.class) != null) {
					return f.getName();
				}
			}
			if(f.getAnnotation(EmbeddedId.class)!=null){
				return f.getName();
			}
		}
		throw new IllegalArgumentException("必须指定@Id属性");
	}
	@Override
	public Exists<T> findById(Class<T> clazz, Serializable id) {
		Exists<T> exists = new Exists<T>();
		try {
			Exists<Field> existsField = ReflectUtil.getFieldValue(clazz, "id", Id.class);
			if (existsField.isExists()) {
				String hql = "select o from " + clazz.getSimpleName() + " o where o."+getIdColumName(clazz)+"=:id";
				Map<String, Object> map = new HashMap<String, Object>();
				map.put("id", id);
				Exists<T> find = selectOne(hql, map);
				return find;
			} else {
				T t = entityManager.find(clazz, id);
				if (t != null) {
					exists.setExists(true);
					exists.setObject(t);
				} else {
					exists.setExists(false);
					exists.setObject(null);
				}
			}
		} catch (Exception e) {
			exists.setExists(false);
			exists.setObject(null);
			e.printStackTrace();
		}
		return exists;
	}

	@SuppressWarnings("unchecked")
	@Override
	public List<T> select(String hql, Map<String, Object> paramters) {
		Query query = entityManager.createQuery(hql);
		for (Entry<String, Object> e : paramters.entrySet()) {
			query.setParameter(e.getKey(), e.getValue());
		}
		return query.getResultList();
	}

	@SuppressWarnings("unchecked")
	@Override
	public List<T> select(String hql, List<Object> parameters) {
		Query query = entityManager.createQuery(hql);
		for (int i = 0; i < parameters.size(); i++) {
			query.setParameter(i, parameters.get(i));
		}
		return query.getResultList();
	}

	@SuppressWarnings("unchecked")
	@Override
	public List<T> selectForUpdate(String hql, List<Object> parameters) {
		Query query = entityManager.createQuery(hql);
		for (int i = 0; i < parameters.size(); i++) {
			query.setParameter(i, parameters.get(i));
		}
		
		List<T> list = query.getResultList();
		return list;
	}

	@SuppressWarnings("unchecked")
	@Override
	public List<T> selectForUpdate(String hql, Map<String, Object> paramters) {
		Query query = entityManager.createQuery(hql);
		query.setLockMode(LockModeType.PESSIMISTIC_WRITE);
		for (Entry<String, Object> e : paramters.entrySet()) {
			query.setParameter(e.getKey(), e.getValue());
		}
		List<T> list = query.getResultList();
		return list;
	}

	@SuppressWarnings("unchecked")
	@Override
	public List<T> selectForUpdate(String hql, Map<String, Object> paramters,Class<Object> c) {
		Query query = entityManager.createNativeQuery(hql,c);
		for (Entry<String, Object> e : paramters.entrySet()) {
			query.setParameter(e.getKey(), e.getValue());
		}

		List<T> list = query.getResultList();
		return list;
	}
	
	@SuppressWarnings("unchecked")
	@Override
	public List<T> selectByName(String namedQuery, Map<String, Object> parameters) {
		Query query = entityManager.createNamedQuery(namedQuery);
		for (Entry<String,Object> entry:parameters.entrySet()) {
			query.setParameter(entry.getKey(), entry.getValue());
		}
		return (List<T>)query.getResultList();
	}

	@SuppressWarnings("unchecked")
	@Override
	public List<T> selectByName(String namedQuery, List<Object> parameters) {
		Query query = entityManager.createNamedQuery(namedQuery);
		for (int i = 0; i < parameters.size(); i++) {
			query.setParameter(i + 1, parameters.get(i));
		}
		return (List<T>)query.getResultList();
	}

	@Override
	public void executeUpdate(String hql, Map<String, Object> parameters) {
		Query query = entityManager.createQuery(hql);
		for (Entry<String, Object> entry : parameters.entrySet()) {
			query.setParameter(entry.getKey(), entry.getValue());
		}
		query.executeUpdate();
	}

	@Override
	public void executeUpdate(String hql, List<Object> parameters) {
		Query query = entityManager.createNamedQuery(hql);
		for (int i = 0; i < parameters.size(); i++) {
			query.setParameter(i + 1, parameters.get(i));
		}
		query.executeUpdate();
	}

	@Override
	public Exists<T> selectOne(String hql, Map<String, Object> paramters) {
		List<T> list = select(hql, paramters);
		Exists<T> exists = new Exists<T>();
		if (list.size() > 0) {
			exists.setExists(true);
			exists.setObject(list.get(0));
		} else {
			exists.setExists(false);
			exists.setObject(null);
		}
		return exists;
	}

	@Override
	public Exists<T> selectOne(String hql, List<Object> paramters) {
		List<T> list = select(hql, paramters);
		Exists<T> exists = new Exists<T>();
		if (list.size() > 0) {
			exists.setExists(true);
			exists.setObject(list.get(0));
		} else {
			exists.setExists(false);
			exists.setObject(null);
		}
		return exists;
	}

	@Override
	public Exists<T> selectOneByName(String namedQuery, Map<String, Object> paramters) {
		List<T> list = selectByName(namedQuery, paramters);
		Exists<T> exists = new Exists<T>();
		if (list.size() > 0) {
			exists.setExists(true);
			exists.setObject(list.get(0));
		} else {
			exists.setExists(false);
			exists.setObject(null);
		}
		return exists;
	}

	@Override
	public Exists<T> selectOneByName(String namedQuery, List<Object> paramters) {
		List<T> list = selectByName(namedQuery, paramters);
		Exists<T> exists = new Exists<T>();
		if (list.size() > 0) {
			exists.setExists(true);
			exists.setObject(list.get(0));
		} else {
			exists.setExists(false);
			exists.setObject(null);
		}
		return exists;
	}

	@Override
	public void executeNativeSQLUpdate(String hql, Map<String, Object> parameters) {
		Query query = entityManager.createNativeQuery(hql);
		for (Entry<String, Object> entry : parameters.entrySet()) {
			query.setParameter(entry.getKey(), entry.getValue());
		}
		query.executeUpdate();
		
	}

	@SuppressWarnings("unchecked")
	@Override
	public List<T> nativeSelect(String hql, Class<Object> c,Map<String, Object> parameters) {
		Query query = entityManager.createNativeQuery(hql,c);
		for (Entry<String, Object> entry : parameters.entrySet()) {
			query.setParameter(entry.getKey(), entry.getValue());
		}
		return query.getResultList();
	}

	@Override
	public List<T> nativeSelect(String hql, Class<Object> c) {
		Map<String ,Object> parametersMap = new HashMap<String	, Object>()	;
		return nativeSelect(hql,c,parametersMap);
	}

	@Override
	public void delete(T t) {
		entityManager.remove(t);
	}

	@Override
	public List<T> nativeSelect(String hql, Map<String, Object> parameters) {
		Query query = entityManager.createNativeQuery(hql);
		for (Entry<String, Object> entry : parameters.entrySet()) {
			query.setParameter(entry.getKey(), entry.getValue());
		}
		return query.getResultList();
	}
}
